package com.ry.novel.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ry.novel.bean.AuthorHolder;
import com.ry.novel.enums.NovelConst;
import com.ry.novel.enums.ResponseStatus;
import com.ry.novel.exception.BusinessException;
import com.ry.novel.mapper.AuthorMapper;
import com.ry.novel.mapper.BookMapper;
import com.ry.novel.mapper.CategoryMapper;
import com.ry.novel.model.dto.BookIndexInfo;
import com.ry.novel.model.dto.BookInfo;
import com.ry.novel.model.dto.condition.BookQuery;
import com.ry.novel.model.dto.condition.BookRankListQuery;
import com.ry.novel.model.dto.condition.CommonQuery;
import com.ry.novel.model.entity.Book;
import com.ry.novel.service.BookIndexService;
import com.ry.novel.service.BookService;
import com.ry.novel.utils.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author ry
 * @since 2022-01-23 10:23
 **/
@Service
@Slf4j
public class BookServiceImpl implements BookService {

    @Autowired
    private BookMapper bookMapper;

    @Autowired
    private BookIndexService bookIndexService;

    @Autowired
    private AuthorMapper authorMapper;

    @Autowired
    private CategoryMapper categoryMapper;


    /**
     * 发布一本小说
     *
     * @param info
     */
    @Override
    public void addBook(BookInfo info) {
        Book entity = new Book();
        entity.setBookName(info.getBookName());
        entity.setAuthorId(AuthorHolder.authorInfo.get().getId());
        entity.setAuthorName(AuthorHolder.authorInfo.get().getPenName());
        entity.setPicUrl(info.getPicUrl());
        entity.setChannel(info.getChannel());
        entity.setCategoryId(info.getCategoryId());
        entity.setCategoryName(info.getCategoryName());
        entity.setBookDesc(info.getBookDesc());
        entity.setState(NovelConst.BOOK_REVIEW_STATE_NORMAL);
        entity.setBookState(NovelConst.BOOK_CONTINUE_STATE_SERIALIZING);
        entity.setVisitCount(0L);
        entity.setWordCount(0L);
        entity.setCommentCount(0L);
        String current = LocalDateTime.now().toString();
        entity.setCreateTime(current);
        entity.setUpdateTime(current);

        bookMapper.insert(entity);
    }

    /**
     * 删除小说，校验一下是不是本人删除的
     *
     * @param id
     */
    @Override
    public void deleteById(Long id) {
        bookMapper.deleteById(id);
    }

    /**
     * 修改小说信息，
     * todo...后面可以校验一下是不是本人修改的
     *
     * @param info
     */
    @Override
    public void updateBook(BookInfo info) {
        Book entity = new Book();
        entity.setId(info.getId());
        entity.setPicUrl(info.getPicUrl());
        entity.setBookName(info.getBookName());
        entity.setChannel(info.getChannel());
        entity.setCategoryId(info.getCategoryId());
        entity.setBookDesc(info.getBookDesc());
        entity.setScore(info.getScore());
        entity.setState(info.getState());
        entity.setBookState(info.getBookState());
        entity.setVisitCount(info.getVisitCount());
        entity.setWordCount(info.getWordCount());
        entity.setCommentCount(info.getCommentCount());
        entity.setLastIndexId(info.getLastIndexId());
        entity.setLastIndexUpdateTime(info.getLastIndexUpdateTime());
        entity.setUpdateTime(LocalDateTime.now().toString());
        entity.setLastIndexName(info.getLastIndexName());

        bookMapper.updateById(entity);
    }

    /**
     * 根据条件分页查询小说接口
     *
     * @param bookQuery
     * @return
     */
    @Override
    public Page<BookInfo> searchByPage(BookQuery bookQuery) {
        log.info(bookQuery.toString());
        Page<Book> entityPage = new Page<>(bookQuery.getPage(),bookQuery.getSize());
        Page<BookInfo> infoPage = new Page<>(bookQuery.getPage(),bookQuery.getSize());
        QueryWrapper<Book> wrapper = new QueryWrapper<>();
        wrapper.gt("word_count",0);
        if (null != bookQuery.getChannel()){
            wrapper.eq("channel",bookQuery.getChannel());
        }
        if (null != bookQuery.getBookState()){
            wrapper.eq("book_state",bookQuery.getBookState());
        }
        if (null != bookQuery.getCategoryId()){
            wrapper.eq("category_id",bookQuery.getCategoryId());
        }

        //总字数,0 三十万字以下 1 三十到五十万字 2 五十到一百万字 3 一百万字以上
        if (null != bookQuery.getWordCount()){
            switch (bookQuery.getWordCount()){
                case 0:
                    wrapper.lt("word_count",30*10000);
                    break;
                case 1:
                    wrapper.gt("word_count",30*10000);
                    wrapper.lt("word_count",50*10000);
                    break;
                case 2:
                    wrapper.gt("word_count",50*10000);
                    wrapper.lt("word_count",100*10000);
                    break;
                case 3:
                    wrapper.gt("word_count",100*10000);
                    break;
                default:
                    throw new BusinessException(ResponseStatus.METHOD_PARAM_ERROR);
            }
        }

        //按更新时间筛选
        // 筛选书籍更新时间 0三日内 1七日内 2半月内 3一月内
        if (null != bookQuery.getUpdateTime()){
            //目标时间
            LocalDateTime targetTime;
            switch (bookQuery.getUpdateTime()){
                case 0:
                    targetTime = LocalDateTime.now().minusDays(3);
                    break;
                case 1:
                    targetTime = LocalDateTime.now().minusDays(7);
                    break;
                case 2:
                    targetTime = LocalDateTime.now().minusDays(15);
                    break;
                case 3:
                    targetTime = LocalDateTime.now().minusDays(30);
                    break;
                default: throw new BusinessException(ResponseStatus.METHOD_PARAM_ERROR);
            }
            wrapper.gt("update_time",targetTime.toString());
        }

        //选择排序方式 0更新时间 1总字数 2点击量
        if (null != bookQuery.getSortWay()){
            switch (bookQuery.getSortWay()){
                case 0:
                    wrapper.orderByDesc("update_time");
                    break;
                case 1:
                    wrapper.orderByDesc("word_count");
                    break;
                case 2:
                    wrapper.orderByDesc("visit_count");
                    break;
                default:
                    throw new BusinessException(ResponseStatus.METHOD_PARAM_ERROR);
            }
        }

        if (null != bookQuery.getKey()){
            wrapper.like("book_name",bookQuery.getKey())
                    .or()
                    .like("author_name",bookQuery.getKey());
        }

        bookMapper.selectPage(entityPage,wrapper);
        
        List<BookInfo> bookInfos = entityPage
                .getRecords()
                .stream()
                .map(entity -> getBookInfo(entity))
                .collect(Collectors.toList());
        infoPage.setRecords(bookInfos);
        infoPage.setTotal(entityPage.getTotal());


        return infoPage;
    }

    private BookInfo getBookInfo(Book entity) {
        BookInfo bookInfo = new BookInfo();
        bookInfo.setId(entity.getId());
        bookInfo.setPicUrl(entity.getPicUrl());
        bookInfo.setBookName(entity.getBookName());
        bookInfo.setAuthorId(entity.getAuthorId());
        bookInfo.setAuthorName(authorMapper.selectById(entity.getAuthorId()).getPenName());
        bookInfo.setChannel(entity.getChannel());
        bookInfo.setCategoryId(entity.getCategoryId());
        bookInfo.setCategoryName(categoryMapper.selectById(entity.getCategoryId()).getName());
        bookInfo.setBookDesc(entity.getBookDesc());
        bookInfo.setScore(entity.getScore());
        bookInfo.setState(entity.getState());
        bookInfo.setBookState(entity.getBookState());
        bookInfo.setVisitCount(entity.getVisitCount());
        bookInfo.setWordCount(entity.getWordCount());
        bookInfo.setCommentCount(entity.getCommentCount());
        bookInfo.setLastIndexId(entity.getLastIndexId());
        bookInfo.setLastIndexUpdateTime(entity.getLastIndexUpdateTime());
        bookInfo.setCreateTime(DateUtil.format(entity.getCreateTime()));
        bookInfo.setUpdateTime(DateUtil.format(entity.getUpdateTime()));
        bookInfo.setLastIndexName(entity.getLastIndexName());

        return bookInfo;
    }


    /**
     * 根据id查询一本小说，这里可能会包含很多信息，后期再加上吧
     * @param id
     * @return
     */
    @Override
    public BookInfo queryById(Long id) {
        Book entity = bookMapper.selectById(id);
        if (entity == null){
            throw new BusinessException(ResponseStatus.BOOK_NOT_EXISTS);
        }
        BookInfo bookInfo = getBookInfo(entity);
        List<BookIndexInfo> lastIndices = bookIndexService.queryLastIndices(id);
        bookInfo.setLastIndices(lastIndices);

        addBookVisitCount(id);

        return bookInfo;
    }

    @Override
    public void addBookVisitCount(Long bookId){
        Book book = bookMapper.selectById(bookId);
        //增加浏览次数
        Long visitCount = book.getVisitCount();
        book.setVisitCount(visitCount + 1);
        bookMapper.updateById(book);
    }

    /**
     * 每次都查前面50条数据
     * 排行榜 0点击榜 1新书榜 2更新榜 3评论榜
     * @param bookRankListQuery@return
     */
    @Override
    public Page<BookInfo> rankingList(BookRankListQuery bookRankListQuery) {
        if (null == bookRankListQuery.getRankListType()){
            throw new BusinessException("未选择排行榜类型");
        }

        Page<Book> entityPage = new Page<>(1,50);
        Page<BookInfo> infoPage = new Page<>(1,50);

        //排行榜类型 0点击榜 1新书榜 2更新榜 3评论榜
        QueryWrapper<Book> wrapper = new QueryWrapper<>();
        String orderBy;
        switch (bookRankListQuery.getRankListType()){
            case 0:
                orderBy = "visit_count";
                break;
            case 1:
                orderBy = "create_time";
                break;
            case 2:
                orderBy = "update_time";
                break;
            case 3:
                orderBy = "comment_count";
                break;
            default:
                throw new BusinessException(ResponseStatus.METHOD_PARAM_ERROR);
        }
        wrapper.orderByDesc(orderBy);
        bookMapper.selectPage(entityPage, wrapper);
        List<BookInfo> infos = entityPage
                .getRecords()
                .stream()
                .map(entity -> getBookInfo(entity))
                .collect(Collectors.toList());
        infoPage.setTotal(entityPage.getTotal());
        infoPage.setRecords(infos);

        return infoPage;
    }

    @Override
    public Page<BookInfo> queryByAuthorId(CommonQuery commonQuery) {
        Long authorId = AuthorHolder.authorInfo.get().getId();
        Page<Book> entityPage = new Page<>(commonQuery.getPage(),commonQuery.getSize());
        Page<BookInfo> infoPage = new Page<>(commonQuery.getPage(),commonQuery.getSize());
        QueryWrapper<Book> wrapper = new QueryWrapper<>();
        wrapper.eq("author_id",authorId);
        bookMapper.selectPage(entityPage, wrapper);

        infoPage.setTotal(entityPage.getTotal());
        List<BookInfo> bookInfos = entityPage
                .getRecords()
                .stream().map(entity -> {
                    BookInfo bookInfo = getBookInfo(entity);

                    return bookInfo;
                }).collect(Collectors.toList());

        infoPage.setRecords(bookInfos);

        return infoPage;
    }

    private List<BookInfo> freshBookList(){
        QueryWrapper<Book> wrapper = new QueryWrapper<>();
        wrapper.gt("word_count",0);
        wrapper.orderByDesc("create_time");
        List<Book> books = bookMapper.selectList(wrapper);

        List<BookInfo> infos = books.stream().filter(entity -> {
            //小说的第一章
            BookIndexInfo indexInfo = bookIndexService.readFirstIndex(entity.getId());
            if (indexInfo == null || !indexInfo.getState().equals(NovelConst.BOOK_INDEX_PASSED)){
                //小说的第一章的状态不是通过审核

                //不添加这本书
                return false;
            }else{
                return true;
            }
        }).limit(6).map(entity -> {
            BookInfo bookInfo = getBookInfo(entity);

            return bookInfo;
        }).collect(Collectors.toList());



        return infos;
    }

    @Override
    public Map<String, List<BookInfo>> readerIndex() {
        Map<String,List<BookInfo>> map = new HashMap<>();
        List<BookInfo> newBooks = freshBookList();
        map.put("newBooks",newBooks);

        return map;
    }

    @Override
    public Page<BookInfo> queryBookByCategory(BookQuery bookQuery) {
        Page<Book> page = new Page<>(bookQuery.getPage(),bookQuery.getSize());
        Page<BookInfo> infoPage = new Page<>(bookQuery.getPage(),bookQuery.getSize());
        QueryWrapper<Book> wrapper = new QueryWrapper<>();
        wrapper.eq("category_id",bookQuery.getCategoryId());
        wrapper.gt("word_count",0);
        bookMapper.selectPage(page, wrapper);

        List<BookInfo> infos = page.getRecords().stream().map(this::getBookInfo).collect(Collectors.toList());

        infoPage.setTotal(page.getTotal());
        infoPage.setRecords(infos);

        return infoPage;
    }

    @Override
    public Page<BookInfo> queryBookByRank(BookQuery bookQuery) {
        Page<Book> entityPage = new Page<>(bookQuery.getPage(),bookQuery.getSize());
        Page<BookInfo> infoPage = new Page<>(bookQuery.getPage(),bookQuery.getSize());

        QueryWrapper<Book> wrapper = new QueryWrapper<>();
        wrapper.gt("word_count",0);
        switch (bookQuery.getRankType()){
            case 0:
                wrapper.orderByDesc("visit_count");
                break;
            case 1:
                wrapper.orderByDesc("create_time");
                break;
            case 2:
                wrapper.orderByDesc("last_index_update_time");
                break;
            case 3:
                wrapper.orderByDesc("comment_count");
                break;
        }
        bookMapper.selectPage(entityPage, wrapper);
        List<BookInfo> bookInfos = entityPage
                .getRecords()
                .stream()
                .map(this::getBookInfo)
                .collect(Collectors.toList());
        infoPage.setTotal(entityPage.getTotal());
        infoPage.setRecords(bookInfos);

        return infoPage;
    }

    private Page<BookInfo> rankByVisitCount(BookQuery bookQuery) {
        Page<Book> entityPage = new Page<>(bookQuery.getPage(),bookQuery.getSize());
        Page<BookInfo> infoPage = new Page<>(bookQuery.getPage(),bookQuery.getSize());

        QueryWrapper<Book> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("visit_count");
        bookMapper.selectPage(entityPage, wrapper);
        List<BookInfo> bookInfos = entityPage
                .getRecords()
                .stream()
                .map(this::getBookInfo)
                .collect(Collectors.toList());
        infoPage.setTotal(entityPage.getTotal());
        infoPage.setRecords(bookInfos);

        return infoPage;
    }
}
